﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PhonePcFileTransfer
{
    public class FileTransferServer
    {
        private string _saveDirectory;
        private readonly string _localIp;
        private readonly int _port;
        private HttpListener _listener;
        private bool _isRunning;

        // 核心优化1：增大缓冲区到64KB（显著减少IO操作次数）
        private const int BUFFER_SIZE = 64 * 1024;
        // 核心优化2：进度更新阈值（每传输1MB更新一次，减少UI开销）
        private const long PROGRESS_UPDATE_THRESHOLD = 1024 * 1024;

        // 事件：用于通知UI状态变化和进度更新
        public event Action<string> OnStatusChanged;
        public event Action<string, long, long> OnTransferProgress;

        public bool IsRunning => _isRunning;
        public string ServerUrl => $"http://{_localIp}:{_port}";

        public FileTransferServer(string saveDirectory, string localIp, int port)
        {
            _saveDirectory = saveDirectory;
            _localIp = localIp;
            _port = port;
        }

        /// <summary>
        /// 启动HTTP服务器（优化：启用TCP_NODELAY减少延迟）
        /// </summary>
        public void Start()
        {
            if (_isRunning) return;

            try
            {
                _listener = new HttpListener();
                _listener.Prefixes.Add($"http://{_localIp}:{_port}/");
                _listener.Prefixes.Add($"http://localhost:{_port}/");
                _listener.Start();

                // 关键优化：设置TCP参数提升传输效率
                SetTcpOptimizations(_listener);

                _isRunning = true;
                OnStatusChanged?.Invoke("服务器已启动，等待连接...");

                // 开始异步处理请求（全异步模式）
                _ = ListenForRequestsAsync();
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"启动服务器失败: {ex.Message}");
                Stop();
            }
        }

        /// <summary>
        /// 优化TCP参数（禁用Nagle算法、增大缓冲区）
        /// </summary>
        private void SetTcpOptimizations(HttpListener listener)
        {
            try
            {
                // 通过反射获取底层TcpListener
                var field = typeof(HttpListener).GetField("m_Listener",
                    BindingFlags.NonPublic | BindingFlags.Instance);

                if (field != null)
                {
                    var tcpListener = field.GetValue(listener) as TcpListener;
                    if (tcpListener != null)
                    {
                        // 禁用Nagle算法（减少小数据包延迟）
                        tcpListener.Server.NoDelay = true;
                        // 增大TCP缓冲区（减少系统调用次数）
                        tcpListener.Server.ReceiveBufferSize = BUFFER_SIZE * 4;
                        tcpListener.Server.SendBufferSize = BUFFER_SIZE * 4;

                        // 解决TcpWindowScale未定义问题：使用数值常量(14)并添加兼容性检查
                        try
                        {
                            // TcpWindowScale的数值为14
                            tcpListener.Server.SetSocketOption(
                                SocketOptionLevel.Tcp,
                                (SocketOptionName)14,
                                8);
                        }
                        catch
                        {
                            // 某些系统不支持此选项，忽略即可
                            OnStatusChanged?.Invoke("当前系统不支持TCP窗口缩放优化，已跳过");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"TCP优化配置警告: {ex.Message}");
            }
        }

        /// <summary>
        /// 异步监听并处理HTTP请求
        /// </summary>
        private async Task ListenForRequestsAsync()
        {
            while (_isRunning)
            {
                try
                {
                    // 异步等待客户端请求（不阻塞线程）
                    var context = await _listener.GetContextAsync().ConfigureAwait(false);

                    // 并行处理请求（使用线程池，不阻塞监听）
                    _ = ProcessRequestAsync(context);
                }
                catch (HttpListenerException ex)
                {
                    // 服务器停止时的异常无需处理
                    if (_isRunning)
                    {
                        OnStatusChanged?.Invoke($"请求监听错误: {ex.Message}");
                    }
                }
                catch (Exception ex)
                {
                    OnStatusChanged?.Invoke($"处理请求时出错: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// 异步处理HTTP请求
        /// </summary>
        private async Task ProcessRequestAsync(HttpListenerContext context)
        {
            var request = context.Request;
            var response = context.Response;

            try
            {
                // 处理首页请求
                if (request.HttpMethod == "GET" && request.Url.LocalPath == "/")
                {
                    await ProcessHomePageRequestAsync(response).ConfigureAwait(false);
                }
                // 处理文件列表请求
                else if (request.HttpMethod == "GET" && request.Url.LocalPath == "/files")
                {
                    await ProcessFileListRequestAsync(response).ConfigureAwait(false);
                }
                // 处理文件上传请求
                else if (request.HttpMethod == "POST" && request.Url.LocalPath == "/upload")
                {
                    await ProcessFileUploadRequestAsync(request, response).ConfigureAwait(false);
                }
                // 处理文件下载请求
                else if (request.HttpMethod == "GET" && request.Url.LocalPath.StartsWith("/download/"))
                {
                    var fileName = WebUtility.UrlDecode(request.Url.LocalPath.Replace("/download/", ""));
                    await ProcessFileDownloadRequestAsync(fileName, response).ConfigureAwait(false);
                }
                // 未找到的请求
                else
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    response.Close();
                }
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"处理请求错误: {ex.Message}");
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                response.Close();
            }
        }

        /// <summary>
        /// 异步处理首页请求
        /// </summary>
        private async Task ProcessHomePageRequestAsync(HttpListenerResponse response)
        {
            try
            {
                string html = GetTransferPageHtml();
                byte[] buffer = Encoding.UTF8.GetBytes(html);

                response.ContentType = "text/html; charset=utf-8";
                response.ContentLength64 = buffer.Length;
                // 异步写入响应流
                await response.OutputStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
                response.Close();
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"处理首页请求错误: {ex.Message}");
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                response.Close();
            }
        }

        /// <summary>
        /// 生成手机端访问的HTML页面（前端优化）
        /// </summary>
        private string GetTransferPageHtml()
        {
            return @"
            <!DOCTYPE html>
            <html>
            <head>
                <meta name='viewport' content='width=device-width, initial-scale=1.0'>
                <title>手机-电脑传文件</title>
                <style>
                    body { font-family: sans-serif; padding: 20px; max-width: 500px; margin: 0 auto; }
                    h2 { color: #333; text-align: center; }
                    .section { margin: 30px 0; padding: 20px; border: 1px solid #ddd; border-radius: 8px; }
                    .btn { background: #4CAF50; color: white; padding: 12px 20px; border: none; border-radius: 4px; 
                           cursor: pointer; width: 100%; font-size: 16px; margin: 10px 0; }
                    .btn:hover { background: #45a049; }
                    #fileInput { display: none; }
                    #progress { height: 20px; background: #eee; margin: 10px 0; display: none; border-radius: 10px; }
                    #progressBar { height: 100%; background: #4CAF50; width: 0%; border-radius: 10px; transition: width 0.3s; }
                    #status { color: #666; margin: 10px 0; }
                    .file-item { padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; }
                    .file-item a { color: #2196F3; text-decoration: none; }
                    .file-size { font-size: 0.9em; color: #888; }
                </style>
            </head>
            <body>
                <h2>文件传输工具</h2>
                
                <!-- 上传区域（手机→电脑） -->
                <div class='section'>
                    <h3>手机 → 电脑</h3>
                    <button class='btn' onclick=""document.getElementById('fileInput').click()"">选择文件上传</button>
                    <input type='file' id='fileInput' multiple onchange='uploadFiles()'>
                    
                    <div id='progress'>
                        <div id='progressBar'></div>
                    </div>
                    <p id='status'></p>
                </div>
                
                <!-- 下载区域（电脑→手机） -->
                <div class='section'>
                    <h3>电脑 → 手机</h3>
                    <p>点击文件下载到手机：</p>
                    <button class='btn' onclick='loadFileList()' style='background:#2196F3;'>刷新文件列表</button>
                    <div id='fileList'>加载文件列表中...</div>
                </div>

                <script>
                    window.onload = function() { loadFileList(); };

                    // 加载文件列表（优化：禁用缓存）
                    function loadFileList() {
                        fetch('/files?t=' + new Date().getTime(), { cache: 'no-store' })
                            .then(res => {
                                if (!res.ok) throw new Error('获取文件列表失败');
                                return res.json();
                            })
                            .then(files => {
                                const listElement = document.getElementById('fileList');
                                listElement.innerHTML = '';
                                if (files.length === 0) {
                                    listElement.innerHTML = '<p>没有可下载的文件</p>';
                                    return;
                                }
                                files.forEach(file => {
                                    const div = document.createElement('div');
                                    div.className = 'file-item';
                                    const nameSpan = document.createElement('span');
                                    nameSpan.innerHTML = file.name;
                                    const sizeSpan = document.createElement('span');
                                    sizeSpan.className = 'file-size';
                                    sizeSpan.innerHTML = file.size;
                                    const link = document.createElement('a');
                                    link.href = '/download/' + encodeURIComponent(file.name);
                                    link.innerHTML = '下载';
                                    div.appendChild(nameSpan);
                                    div.appendChild(sizeSpan);
                                    div.appendChild(link);
                                    listElement.appendChild(div);
                                });
                            })
                            .catch(err => {
                                document.getElementById('fileList').innerHTML = '<p>加载失败: ' + err.message + '</p>';
                            });
                    }

                    // 上传文件（前端优化：控制进度更新频率）
                    function uploadFiles() {
                        const input = document.getElementById('fileInput');
                        if (input.files.length === 0) return;

                        const formData = new FormData();
                        for (let i = 0; i < input.files.length; i++) {
                            formData.append('files', input.files[i]);
                        }

                        const xhr = new XMLHttpRequest();
                        xhr.open('POST', '/upload');
                        xhr.withCredentials = false; // 减少HTTP头开销

                        // 控制进度更新频率（每100ms一次，避免UI阻塞）
                        let lastProgressTime = 0;
                        xhr.upload.onprogress = function(e) {
                            if (e.lengthComputable) {
                                const now = Date.now();
                                if (now - lastProgressTime > 100) {
                                    const percent = (e.loaded / e.total) * 100;
                                    document.getElementById('progress').style.display = 'block';
                                    document.getElementById('progressBar').style.width = percent + '%';
                                    document.getElementById('status').textContent = `上传中: ${Math.round(percent)}%`;
                                    lastProgressTime = now;
                                }
                            }
                        };

                        xhr.onload = function() {
                            document.getElementById('status').textContent = xhr.status === 200 ? '上传成功！' : '上传失败: ' + xhr.statusText;
                            if (xhr.status === 200) loadFileList();
                            setTimeout(() => {
                                document.getElementById('progress').style.display = 'none';
                                document.getElementById('status').textContent = '';
                            }, 2000);
                        };

                        xhr.onerror = function() {
                            document.getElementById('status').textContent = '上传出错，请重试';
                        };

                        xhr.send(formData);
                    }
                </script>
            </body>
            </html>";
        }

        /// <summary>
        /// 更新服务器的保存目录
        /// </summary>
        public void SetSaveDirectory(string newDirectory)
        {
            if (string.IsNullOrEmpty(newDirectory))
            {
                OnStatusChanged?.Invoke("错误：新目录路径为空，未更新");
                return;
            }

            if (!Directory.Exists(newDirectory))
            {
                OnStatusChanged?.Invoke($"错误：目录不存在 ({newDirectory})，未更新");
                return;
            }

            _saveDirectory = newDirectory;
            OnStatusChanged?.Invoke($"服务器保存目录已更新为：{_saveDirectory}");
        }

        /// <summary>
        /// 异步处理文件列表请求
        /// </summary>
        private async Task ProcessFileListRequestAsync(HttpListenerResponse response)
        {
            try
            {
                if (!Directory.Exists(_saveDirectory))
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    response.Close();
                    return;
                }

                // 异步获取文件信息（避免阻塞IO线程）
                var files = await Task.Run(() =>
                {
                    return Directory.GetFiles(_saveDirectory)
                        .Select(path => new
                        {
                            name = Path.GetFileName(path),
                            size = new FileInfo(path).Length.FormatSize(),
                            lastModified = new FileInfo(path).LastWriteTime
                        })
                        .OrderByDescending(f => f.lastModified)
                        .ToList();
                }).ConfigureAwait(false);

                // 异步序列化JSON
                byte[] buffer;
                using (var stream = new MemoryStream())
                {
                    await System.Text.Json.JsonSerializer.SerializeAsync(stream, files).ConfigureAwait(false);
                    buffer = stream.ToArray();
                }

                response.ContentType = "application/json; charset=utf-8";
                response.ContentLength64 = buffer.Length;
                await response.OutputStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
                response.Close();
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"处理文件列表请求错误: {ex.Message}");
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                response.Close();
            }
        }

        /// <summary>
        /// 异步处理文件上传请求（核心优化点）
        /// </summary>
        private async Task ProcessFileUploadRequestAsync(HttpListenerRequest request, HttpListenerResponse response)
        {
            try
            {
                if (!request.ContentType.StartsWith("multipart/form-data"))
                {
                    response.StatusCode = (int)HttpStatusCode.UnsupportedMediaType;
                    response.Close();
                    return;
                }

                // 解析boundary
                int boundaryStart = request.ContentType.IndexOf("boundary=") + 9;
                string boundary = request.ContentType.Substring(boundaryStart);
                byte[] boundaryBytes = Encoding.UTF8.GetBytes($"--{boundary}");
                int boundaryLength = boundaryBytes.Length;

                using (var inputStream = request.InputStream)
                {
                    byte[] buffer = new byte[BUFFER_SIZE];
                    int bytesRead;
                    string fileName = null;
                    Stream fileStream = null;
                    long totalReceived = 0;
                    long lastProgressUpdate = 0;

                    try
                    {
                        // 读取文件内容（全异步）
                        while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
                        {
                            totalReceived += bytesRead;

                            // 查找文件名（仅第一次需要）
                            if (fileName == null)
                            {
                                string content = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                                if (content.Contains("filename="))
                                {
                                    int startIndex = content.IndexOf("filename=\"") + 10;
                                    int endIndex = content.IndexOf("\"", startIndex);
                                    fileName = content.Substring(startIndex, endIndex - startIndex);
                                    fileName = SanitizeFileName(fileName);

                                    // 创建文件流
                                    string filePath = Path.Combine(_saveDirectory, fileName);
                                    filePath = GetUniqueFilePath(filePath);
                                    fileStream = File.Create(filePath);

                                    OnStatusChanged?.Invoke($"开始接收文件: {fileName}");

                                    // 写入文件内容起始部分
                                    int contentStart = content.IndexOf("\r\n\r\n", startIndex) + 4;
                                    if (contentStart < bytesRead)
                                    {
                                        int initialContentLength = bytesRead - contentStart;
                                        await fileStream.WriteAsync(buffer, contentStart, initialContentLength).ConfigureAwait(false);

                                        // 首次更新进度
                                        lastProgressUpdate = initialContentLength;
                                        OnTransferProgress?.Invoke(fileName, lastProgressUpdate, request.ContentLength64);
                                    }
                                }
                            }
                            // 写入文件内容
                            else if (fileStream != null)
                            {
                                bool foundBoundary = false;
                                // 检查是否到达边界
                                for (int i = 0; i < bytesRead - boundaryLength; i++)
                                {
                                    bool match = true;
                                    for (int j = 0; j < boundaryLength; j++)
                                    {
                                        if (buffer[i + j] != boundaryBytes[j])
                                        {
                                            match = false;
                                            break;
                                        }
                                    }

                                    if (match)
                                    {
                                        // 写入边界前的内容
                                        if (i > 0)
                                        {
                                            await fileStream.WriteAsync(buffer, 0, i - 2).ConfigureAwait(false);
                                            totalReceived -= (bytesRead - i + 2);
                                        }
                                        foundBoundary = true;
                                        break;
                                    }
                                }

                                if (foundBoundary)
                                {
                                    // 文件传输完成
                                    break;
                                }
                                else
                                {
                                    // 写入所有内容
                                    await fileStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);

                                    // 控制进度更新频率（每1MB更新一次）
                                    if (totalReceived - lastProgressUpdate >= PROGRESS_UPDATE_THRESHOLD)
                                    {
                                        OnTransferProgress?.Invoke(fileName, totalReceived, request.ContentLength64);
                                        lastProgressUpdate = totalReceived;
                                    }
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (fileStream != null)
                        {
                            await fileStream.FlushAsync().ConfigureAwait(false);
                            fileStream.Dispose();

                            if (!string.IsNullOrEmpty(fileName))
                            {
                                OnStatusChanged?.Invoke($"文件接收完成: {fileName}");
                                OnTransferProgress?.Invoke(fileName, totalReceived, request.ContentLength64);
                            }
                        }
                    }
                }

                response.StatusCode = (int)HttpStatusCode.OK;
                response.Close();
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"处理文件上传错误: {ex.Message}");
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                response.Close();
            }
        }

        /// <summary>
        /// 异步处理文件下载请求（核心优化点）
        /// </summary>
        private async Task ProcessFileDownloadRequestAsync(string fileName, HttpListenerResponse response)
        {
            try
            {
                if (string.IsNullOrEmpty(fileName))
                {
                    response.StatusCode = (int)HttpStatusCode.BadRequest;
                    response.Close();
                    return;
                }

                string filePath = Path.Combine(_saveDirectory, fileName);
                if (!File.Exists(filePath))
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    response.Close();
                    return;
                }

                // 打开文件流（使用异步文件打开）
                using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, BUFFER_SIZE, true))
                {
                    // 设置响应头（关闭Chunked编码，减少开销）
                    response.ContentType = "application/octet-stream";
                    response.AddHeader("Content-Disposition", $"attachment; filename=\"{WebUtility.UrlEncode(fileName)}\"");
                    response.ContentLength64 = fileStream.Length;
                    response.SendChunked = false; // 禁用分块编码

                    byte[] buffer = new byte[BUFFER_SIZE];
                    int bytesRead;
                    long totalSent = 0;
                    long lastProgressUpdate = 0;

                    // 异步读取并发送文件内容
                    while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
                    {
                        await response.OutputStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
                        totalSent += bytesRead;

                        // 控制进度更新频率（每1MB更新一次）
                        if (totalSent - lastProgressUpdate >= PROGRESS_UPDATE_THRESHOLD)
                        {
                            OnTransferProgress?.Invoke(fileName, totalSent, fileStream.Length);
                            lastProgressUpdate = totalSent;
                        }
                    }

                    // 确保所有数据发送完成
                    await response.OutputStream.FlushAsync().ConfigureAwait(false);
                }

                OnStatusChanged?.Invoke($"文件发送完成: {fileName}");
                OnTransferProgress?.Invoke(fileName, 0, 0); // 重置进度
                response.Close();
            }
            catch (Exception ex)
            {
                OnStatusChanged?.Invoke($"处理文件下载错误: {ex.Message}");
                response.StatusCode = (int)HttpStatusCode.InternalServerError;
                response.Close();
            }
        }

        /// <summary>
        /// 清理文件名，移除不合法字符
        /// </summary>
        private string SanitizeFileName(string fileName)
        {
            foreach (char c in Path.GetInvalidFileNameChars())
            {
                fileName = fileName.Replace(c, '_');
            }
            return fileName;
        }

        /// <summary>
        /// 获取唯一的文件路径，如果文件已存在则添加序号
        /// </summary>
        private string GetUniqueFilePath(string filePath)
        {
            if (!File.Exists(filePath))
                return filePath;

            string directory = Path.GetDirectoryName(filePath);
            string fileName = Path.GetFileNameWithoutExtension(filePath);
            string extension = Path.GetExtension(filePath);

            int counter = 1;
            while (true)
            {
                string newFilePath = Path.Combine(directory, $"{fileName}_{counter}{extension}");
                if (!File.Exists(newFilePath))
                    return newFilePath;
                counter++;
            }
        }

        /// <summary>
        /// 停止服务器
        /// </summary>
        public void Stop()
        {
            _isRunning = false;

            if (_listener != null)
            {
                try
                {
                    _listener.Stop();
                    _listener.Close();
                }
                catch (Exception ex)
                {
                    OnStatusChanged?.Invoke($"停止服务器时出错: {ex.Message}");
                }
                finally
                {
                    _listener = null;
                }
            }

            OnStatusChanged?.Invoke("服务器已停止");
        }
    }

    /// <summary>
    /// 扩展方法：格式化文件大小显示
    /// </summary>
    public static class FileSizeFormatter 
    {
        // 方法名保持不变，通过类名区分
        public static string FormatSize(this long bytes)
        {
            if (bytes < 1024) return $"{bytes} B";
            if (bytes < 1024 * 1024) return $"{(bytes / 1024.0):F1} KB";
            if (bytes < 1024 * 1024 * 1024) return $"{(bytes / (1024.0 * 1024.0)):F1} MB";
            return $"{(bytes / (1024.0 * 1024.0 * 1024.0)):F1} GB";
        }
    }

}
